package com.minarto.ui {
	import de.polygonal.core.ObjectPool;
	import com.minarto.events.CustomEvent;
	import com.minarto.utils.GPool;
	import flash.display.Stage;
	import flash.ui.Keyboard;
	import com.minarto.events.KeyEvtObj;
	import flash.text.*;
	import flash.events.KeyboardEvent;
	
	
	/**
	 * @author KIMMINHWAN
	 */
	public class KeyboardManager {
		static private var _instance:KeyboardManager;
		static public function getInstance():KeyboardManager {
			return	_instance;
		}
		
		
		static public function init($stage:Stage):KeyboardManager {
			_instance = new KeyboardManager($stage);
			return	_instance;
		}
		
		
		private var _downList:Vector.<KeyEvtObj> = new <KeyEvtObj>[],
					_upList:Vector.<KeyEvtObj> = new <KeyEvtObj>[],
					_lastKeyEvt:KeyEvtObj,
					_copyText:String;
					
		
		protected var stage:Stage;
		
		public function KeyboardManager($stage:Stage) {
			if (_instance) {
				throw new Error("don't create instance");
			}
			
			stage = $stage;
			
			$stage.addEventListener(KeyboardConst.KEY_REGISTER, onEvtRegister, false, 0, true);
			$stage.addEventListener(KeyboardConst.KEY_UNREGISTER, onEvtUnregister, false, 0, true);
			$stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown, false, 0, true);
			$stage.addEventListener(KeyboardEvent.KEY_UP, keyUp, false, 0, true);
		}
		
		
		protected function onEvtRegister($e:CustomEvent):void {
			var param:* = $e.param;
			
			var keyObj:KeyEvtObj = GPool.getPool(KeyEvtObj).object;
			keyObj.code = param.code;
			keyObj.alt = param.alt;
			keyObj.shift = param.shift;
			keyObj.ctrl = param.ctrl;
			keyObj.handler = param.handler;
			keyObj.handlerArgs = param.handlerArgs;
			
			if(param.type === KeyboardEvent.KEY_DOWN){
				_downList.push(keyObj);
			}
			else{
				_upList.push(keyObj);
			}
		}
		
		
		protected function onEvtUnregister($e:CustomEvent):void {
			var keyObj:KeyEvtObj, i:uint;
			
			var param:* = $e.param;
			
			var p:ObjectPool = GPool.getPool(KeyEvtObj);
			
			if(param.type === KeyboardEvent.KEY_DOWN){
				var list:Vector.<KeyEvtObj> = _downList;
			}
			else{
				list = _upList;
			}
			
			
			var code:uint = param.code;
			var alt:Boolean = param.alt;
			var shift:Boolean = param.shift;
			var ctrl:Boolean = param.ctrl;
			
			i = list.length;
			while(i --){
				keyObj = list[i];
				if(keyObj.code === code && keyObj.shift === shift && keyObj.alt === alt && keyObj.ctrl === ctrl) {
					list.splice(i, 1);
					p.object = keyObj;
					return;
				}
			}
		}
		
		
		protected function keyDown($e:KeyboardEvent):void{
			var t:TextField, i:uint, keyEvt:KeyEvtObj, code:uint, shift:Boolean, alt:Boolean, ctrl:Boolean;
			
			t = stage.focus as TextField;
			
			code = $e.keyCode;
			shift = $e.shiftKey;
			alt = $e.altKey;
			ctrl = $e.ctrlKey;
			
			if(t && t.type == TextFieldType.INPUT){
				if(ctrl && !alt && !shift){
					if(code === Keyboard.C) {
						_copyText = t.text.substring(t.selectionBeginIndex, t.selectionEndIndex);
					}
					else if(code === Keyboard.V && _copyText) {
						t.replaceText(t.selectionBeginIndex, t.selectionEndIndex, _copyText);
					}
				}
			}
			else{
				if(_lastKeyEvt && _lastKeyEvt.code === code && _lastKeyEvt.shift === shift && _lastKeyEvt.alt === alt && _lastKeyEvt.ctrl === ctrl){
					return;
				}
				else{
					i = _downList.length;
					while(i --){
						keyEvt = _downList[i];
						if(keyEvt.code === code && keyEvt.shift === shift && keyEvt.alt === alt && keyEvt.ctrl === ctrl) {
							keyEvt.handler.apply(null, keyEvt.handlerArgs);
							_lastKeyEvt = keyEvt;
							break;
						}
					}
				}
			}
		}
		
		
		protected function keyUp($e:KeyboardEvent):void{
			_lastKeyEvt = null;
			
			var t:TextField, i:uint, keyEvt:KeyEvtObj, code:uint, shift:Boolean, alt:Boolean, ctrl:Boolean;
			
			t = stage.focus as TextField;
			
			code = $e.keyCode;
			shift = $e.shiftKey;
			alt = $e.altKey;
			ctrl = $e.ctrlKey;
			
			if(t && t.type == TextFieldType.INPUT){
				if(ctrl && !alt && !shift){
					if(code === Keyboard.C) {
						_copyText = t.text.substring(t.selectionBeginIndex, t.selectionEndIndex);
					}
					else if(code === Keyboard.V && _copyText) {
						t.replaceText(t.selectionBeginIndex, t.selectionEndIndex, _copyText);
					}
				}
			}
			else{
				i = _downList.length;
				while(i --){
					keyEvt = _downList[i];
					if(keyEvt.code === code && keyEvt.shift === shift && keyEvt.alt === alt && keyEvt.ctrl === ctrl) {
						keyEvt.handler.apply(null, keyEvt.handlerArgs);
						break;
					}
				}
			}
		}
	}
}
